package com.lee.study.nettty.server.config;

import java.net.InetSocketAddress;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.annotation.Scope;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;

import com.lee.study.nettty.server.handler.StringProtocolInitalizer;


@Configuration
@ComponentScan("com.lee")
@PropertySource("classpath:netty-server.properties")
public class SpringConfig {

	@Value("${boss.thread.count}")
	private int bossCount;
	
	@Value("${worker.thread.count}")
	private int workerCount;
	
	@Value("${tcp.port}")
	private int tcpPort;
	
	@Value("${so.keepalive}")
	private boolean keepAlive;

	@Value("${so.backlog}")
	private int backlog;
	
	@Value("${log4j.configuration}")
	private String log4jConfiguration;

	@Autowired
	@Qualifier("springProtocolInitializer")
	private StringProtocolInitalizer protocolInitalizer;
	
	@Bean(name="serverBootstrap")
	public ServerBootstrap bootstrap(){
		ServerBootstrap b = new ServerBootstrap();
		b.group(bossGroup(),workerGroup())
			.channel(NioServerSocketChannel.class)
			.handler(new LoggingHandler(LogLevel.INFO))
			.childHandler(protocolInitalizer);
		
		Map<ChannelOption<?>,Object> tcpChannelOptions = tcpChannelOptions();
		Set<ChannelOption<?>> keySet = tcpChannelOptions.keySet();
		
		
		for (@SuppressWarnings("rawtypes")
		ChannelOption option : keySet) {
			b.option(option, tcpChannelOptions.get(option));
		}
		return b;
	}
	
	@Bean(name="bossGroup",destroyMethod="shutdownGracefully")
	public NioEventLoopGroup bossGroup(){
		return new NioEventLoopGroup(bossCount);
	}
	
	@Bean(name = "workerGroup",destroyMethod="shutdownGracefully")
	public NioEventLoopGroup workerGroup(){
		return new NioEventLoopGroup(workerCount);
	}
	
	@Bean(name = "tcpChannelOptions")
	public Map<ChannelOption<?>,Object> tcpChannelOptions(){
		Map<ChannelOption<?>,Object> options = new HashMap<ChannelOption<?>,Object>();
		options.put(ChannelOption.SO_KEEPALIVE, keepAlive);
		options.put(ChannelOption.SO_BACKLOG, backlog);
		return options;
	}
	
	@Bean(name="tcpSocketAddress")
	public InetSocketAddress tcpPort(){
		return new InetSocketAddress(tcpPort);
	}
	
	@Bean(name = "stringEncoder")
	@Scope()
	public StringEncoder stringEncoder(){
		return new StringEncoder();
	}
	
	@Bean(name = "stringDecoder")
	public StringDecoder stringDecoder(){
		return new StringDecoder();
	}
	
	@Bean
	public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer(){
		return new PropertySourcesPlaceholderConfigurer();
	}
}
